
var EXPORTED_SYMBOLS = ["CommonDialogRouter"];

let CommonDialogRouter = ( function () {
    "use strict";

    const Cu = Components.utils;
    const Ci = Components.interfaces;
    const Cc = Components.classes;
    function require(url) {
        let scope = {};
        Cu.import(url, scope);
        return scope;
    }
    let {MiscUtils} = require("chrome://jsm/content/utils.js");
    let {Services} = require("resource://gre/modules/Services.jsm");
    let {Storage} = require("chrome://jsm/content/Storage.js");
    let {RuntimeError} = require("chrome://jsm/content/Exceptions.js");
    let {console} = require("resource://gre/modules/devtools/Console.jsm");

    return {
        states: new WeakMap(),

        updateState(win, state) {
            this.states.set(win, state);
            this.broadcastMessage("state-changed", state);
        },

        addDialogAction(win, action) {
            this.broadcastMessage("add-dialog-action",
                                  {winId: win.iMacros.wid, action: action});
        },

        whenReady(win) {
            return new Promise((resolve, reject) => {
                if (win.document && win.document.readyState == "complete")
                    return resolve(win);
                else
                    win.addEventListener("load", function l() {
                        win.removeEventListener("load", l);
                        resolve(win);
                    }, false)
            });
        },

        wmListener: {
            onOpenWindow(xulwin) {
                let win = xulwin.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);
                CommonDialogRouter.whenReady(win).then(win => {
                    let type = win.document.documentElement
                        .getAttribute("windowtype");
                    if (type == "navigator:browser")
                        CommonDialogRouter.updateState(win, {
                            winId: win.iMacros.wid,
                            state: "idle"
                        });
                });
            },

            onCloseWindow(xulwin) {
                let win = xulwin.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);
                CommonDialogRouter.states.delete(win);
            }
        },

        init() {
            let windows = Services.wm.getEnumerator("navigator:browser");
            while (windows.hasMoreElements()) {
                let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
                this.whenReady(win).then(win => {
                    this.updateState(win, {winId: win.iMacros.wid, state: "idle"});
                });
            }
            Services.wm.addListener(this.wmListener);
            Services.obs.addObserver(this, "imacros-state-change", false);
            Services.obs.addObserver(this, "imacros-ondialog-action", false);
            ["dlg-hook", "dlg-hook-error"].forEach(topic => {
                Services.ppmm.addMessageListener("imacros:"+topic, this);
            });
            
        },

        terminate() {
            Services.wm.removeListener(this.wmListener);
            Services.obs.removeObserver(this, "imacros-state-change");
            Services.obs.removeObserver(this, "imacros-ondialog-action");
            this.broadcastMessage("terminate");
            ["dlg-hook", "dlg-hook-error"].forEach(topic => {
                Services.ppmm.removeMessageListener("imacros:"+topic, this);
            });
        },

        broadcastMessage(topic, data) {
            Services.ppmm.broadcastAsyncMessage("imacros:"+topic, data);
        },

        receiveMessage(msg) {
            
            let win = Services.wm.getMostRecentWindow("navigator:browser");
            if (msg.name == "imacros:dlg-hook") {
                
                Services.obs.notifyObservers(
                    win, "imacros-commdlg-hook", JSON.stringify(msg.data)
                );
            } else if (msg.name == "imacros:dlg-hook-error") {
                if (win.iMacros.playing && !win.iMacros.player.ignoreErrors) {
                    let e = new RuntimeError(msg.data.message, msg.data.errnum);
                    win.iMacros.player.stop(e);
                }
            }
        },
        
        observe(subj, topic, data) {
            if (topic == "imacros-state-change") {
                if (!this.states.has(subj))
                    console.error("State changed for window not in map!");
                this.updateState(subj, {winId: subj.iMacros.wid, state: data});
            } else if (topic == "imacros-ondialog-action") {
                this.addDialogAction(subj, JSON.parse(data));
            }
        }
    };
})();
